#include <pthread.h>

typedef struct __account_t {
    pthread_mutex_t mut;
    double balance;
} account_t;


typedef struct __rm_t {
	// 记录已经被用的锁
	set_t<account_t> used;
	// 用于保证 used 的线程安全
	pthread_mutex_t lock;
} rm_t;

// 同时申请 from 和 to 两个账户的锁
// 如果申请到了，则返回 true
// 否则，有一个锁拿不到的话，则返回 false
int rm_apply(rm_t *rm, account_t *from, account_t *to) {
	pthread_mutex_lock(&rm->lock);
	// 如果有一个资源被其他线程占用，则直接申请不成功
	if (rm->used.contains(from) || rm->used.contains(to)) {
		return 0;
	} else {
		// 否则，一起申请两个账户资源
		rm->used.add(from);
        rm->used.add(to);
		return 1;
	}
	pthread_mutex_unlock(&rm->lock);
}

// 同时还回 from 和 to 两个账户的锁
void rm_free(rm_t *rm, account_t *from, account_t *to) {
	pthread_mutex_lock(&rm->lock);
	rm->used.remove(from);
    rm->used.remove(to);
	pthread_mutex_unlock(&rm->lock);
}

// 转账，从 src 账户往 target 账户上转 amt 元
void transfer(rm_t *rm, 
				account_t *src,
                account_t *target,
                double amt) {
	// 一次性申请转出账户和转入账户的资源，直到申请成功
	while (!rm_apply(rm, src, target));
	
	pthread_mutex_lock(&src->mut);
	pthread_mutex_lock(&target->mut);
    if (src->balance > amt) {
        src->balance -= amt;
        target->balance += amt;
    }
    pthread_mutex_unlock(&target->mut);
    pthread_mutex_unlock(&src->mut);
	
	rm_free(rm, src, target);
}
